/* Copyright (c) CERN
 * * Artistic License 2.0
 * */

import java.util.Random;
import java.lang.Math;
import java.util.Arrays;

/**
 * Pseudo distribution based on real data
 *
 * @author Xavier Grehant
 */
public class Actual extends DistroUtils implements Distro {

/**
 * Parameters of the distribution: actual data
 */
   int[] params;

/**
 * Uniform random distribution
 */
   Random rand;

/**
 * Constructor taking the sample set.
 * @param array sample set
 */
   public Actual(int[] array) {
      this.params = array;
      Arrays.sort(params);
      rand = new Random();
   }

/**
 * Integer Array flip
 * @return flipped array.
 * @param array array to flip.
 */
   int[] flip(int[] array) {
      int[] output = new int[array.length];
      for (int k = 0; k < array.length; k++)
         output[array.length - 1 - k] = array[k];
      return output;
   }

/**
 * Single-point inverse cdf
 * @return a value given the probability to obtain less.
 * @param value the probability to obtain less.
 */
   double icdf(double value) {
      int index = (int) (value * params.length);
      if (index == params.length) index --;
      return params[index];
   }

/**
 * Inverse cdf
 * @return the value of the function at the initial points.
 */
   double[] icdf() {
      double[] output = new double[params.length];
      for (int i = 0; i < params.length; i++) output[i] = (double) params[i];
      return output;
   }

/**
 * Random number generator according to the pseudo-distribution.
 * @return random number according to the pseudo-distribution.
 */
   public double nextDouble() {
      return icdf(rand.nextDouble());
   }

/**
 * Cumulative density function of the pseudo-distribution.
 * @return P(X <= x)
 * @param value the point at which the cdf is calculated.
 */
   public double cdf(double value) {
      double[] values = icdf();
      int n;
      for (n = 0; n < values.length; n++) if (values[n] >= value) break;
      return ((double) n) / values.length;
   }
}
